#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define SIZ 128
int server_process(char* sock_path, int* serv)
{
    int server, client, t, len;
    struct sockaddr_un local, remote;
    char *str = malloc(SIZ*sizeof(char));
    if ((server = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }
    *serv = server;
    local.sun_family = AF_UNIX;
    strcpy(local.sun_path, sock_path);
    unlink(local.sun_path);
    len = strlen(local.sun_path) + sizeof(local.sun_family);
    if (bind(server, (struct sockaddr *)&local, len) == -1) {
        perror("bind");
        exit(1);
    }
    if (listen(server, 5) == -1) {
        perror("listen");
        exit(1);
    }
    printf("Waiting for a connection...\n");
    t = sizeof(remote);
    if ((client = accept(server, (struct sockaddr *)&remote, &t)) == -1) {
        perror("accept");
        exit(1);
    }
    printf("Connected.\n");

    return client;
}

int client_process(char* sock_path)
{
    int sock, t, len;
    struct sockaddr_un remote;
    if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }
    printf("Trying to connect...\n");
    remote.sun_family = AF_UNIX;
    strcpy(remote.sun_path, sock_path);
    len = strlen(remote.sun_path) + sizeof(remote.sun_family);
    while(connect(sock, (struct sockaddr *)&remote, len) == -1) {
        perror("connect");
        sleep(1);
    }
    printf("Connected.\n");
    return sock;
}

void* enter()
{
    unsigned long pid = (unsigned long) getpid();
    char* str = malloc(SIZ*sizeof(char));
    int server, client;
    char* msg = "hello";
    char sock_path[SIZ];
    sprintf(sock_path, "./%lu", pid);
    client = server_process(sock_path, &server);

    int n = read(client, str, SIZ);
    str[n] = '\0';
    printf("Enter Process %lu receives a message: %s\n", pid, str);

    if (write(client, msg,strlen(msg)) == -1) {
        perror("send");
        exit(1);
    }
    printf("Enter Process %lu sends a message: %s\n",pid,msg);

    close(server);
    remove(sock_path);
}

void* depart(pid_t ot){
    unsigned long pid = (unsigned long) getpid();
    unsigned long ot_pid = (unsigned long) ot;
    int sock;
    char* str = malloc(SIZ*sizeof(char));
    char* msg = "hello";
    char sock_path[SIZ];
    sprintf(sock_path, "./%lu", ot_pid);

    sock = client_process(sock_path);
    if (write(sock, msg,strlen(msg)) == -1) {
        perror("send");
        exit(1);
    }
    printf("Depart Process %lu sends a message: %s\n",pid,msg);

    int n = read(sock, str, SIZ);
    str[n] = '\0';
    printf("Depart Process %lu receives a message: %s\n", pid, str);
    close(sock);
    /*remove(sock_path);*/
}

int main(int argc, const char *argv[])
{
    pid_t pid = fork();
    if (pid<0) {
        perror("fork error!\n");
        exit(1);
    } else if (pid==0){
        enter();
    } else {
        depart(pid);
    }
    exit(0);
}
